#include "alttileset.h"

namespace Alt {
     //TilesetData
     TilesetData::TilesetData(const QImage& image, const QSize& tileSize, const QPoint& padding){
          this->image = image;
          this->tileSize = tileSize;
          this->padding = padding;
     }

     TilesetData::TilesetData(const TilesetData& other) : QSharedData(other) {
          image = other.image;
          tileSize = other.tileSize;
          padding = other.padding;
     }

     //Tileset
     Tileset::Tileset(const QImage& image, const QSize& tileSize, const QPoint& padding){
          m_data = new TilesetData(image, tileSize, padding);
     }

     Tileset::Tileset(const Tileset& other){
          m_data = other.m_data;
     }

     int Tileset::columnCount() const {
          Q_ASSERT_X(tileSize().isValid(), "calculating column count", "invalid tile size.");
          return image().width() / paddedTileWidth();
     }

     int Tileset::horizontalPadding() const {
          return m_data->padding.x();
     }

     const QImage& Tileset::image() const {
          return m_data->image;
     }

     bool Tileset::isValid() const {
          return (image().isNull() && tileSize().isValid());
     }

     int Tileset::maxTileNumber() const {
          return rowCount() * columnCount() - 1;
     }

     int Tileset::paddedTileHeight() const {
          return tileHeight() + verticalPadding();
     }

     QSize Tileset::paddedTileSize() const {
          return QSize(paddedTileWidth(), paddedTileHeight());
     }

     int Tileset::paddedTileWidth() const {
          return tileWidth() + horizontalPadding();
     }

     const QPoint& Tileset::padding() const {
          return m_data->padding;
     }

     int Tileset::rowCount() const {
          Q_ASSERT_X(tileSize().isValid(), "calculating row count", "invalid tile size.");
          return image().height() / paddedTileHeight();
     }

     void Tileset::setHorizontalPadding(int hPadding){
          if((horizontalPadding() != hPadding) && (hPadding >= 0)){
               m_data->padding = QPoint(hPadding, verticalPadding());
          }
          return;
     }

     void Tileset::setImage(const QImage& image){
          if(this->image() != image){
               m_data->image = image;
          }
          return;
     }

     void Tileset::setPadding(const QPoint& padding){
          if(this->padding() != padding){
               m_data->padding = padding;
          }
          return;
     }

     void Tileset::setTileHeight(int height){
          if((tileHeight() != height) && (height >= 0)){
               m_data->tileSize = QSize(tileWidth(), height);
          }
          return;
     }

     void Tileset::setTileSize(const QSize& tileSize){
          if(this->tileSize() != tileSize){
               m_data->tileSize = tileSize;
          }
          return;
     }

     void Tileset::setTileWidth(int width){
          if((tileWidth() != width) && (width >= 0)){
               m_data->tileSize = QSize(width, tileHeight());
          }
          return;
     }

     QSize Tileset::size() const {
          return QSize(columnCount(), rowCount());
     }

     QRect Tileset::tileRect(int tileNumber) const {
          int max = maxTileNumber();
          bool negative = tileNumber < 0;
          tileNumber = qAbs(tileNumber);
          tileNumber %= (max + 1);
          if(negative){
               tileNumber = max - tileNumber;
          }
          int x = (tileNumber % columnCount()) * paddedTileWidth();
          int y = (tileNumber / columnCount()) * paddedTileHeight();
          return QRect(QPoint(x, y), tileSize());

     }

     int Tileset::tileHeight() const {
          return m_data->tileSize.height();
     }

     const QSize& Tileset::tileSize() const {
          return m_data->tileSize;
     }

     int Tileset::tileWidth() const {
          return m_data->tileSize.width();
     }

     int Tileset::verticalPadding() const {
          return m_data->padding.y();
     }

     QDataStream& operator << (QDataStream& stream, const Tileset& tileset) {
          return stream << tileset.image() << tileset.tileSize() << tileset.padding();
     }

     QDataStream& operator >> (QDataStream& stream, Tileset& tileset) {
          QImage image;
          QSize tileSize;
          QPoint padding;
          stream >> image >> tileSize >> padding;
          tileset.setImage(image);
          tileset.setTileSize(tileSize);
          tileset.setPadding(padding);
          return stream;
     }
}
